#include "armfunction.h"

#include <functional>
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>

#include "armblock.h"
#include "arminst.h"

void ArmFunction::Simplify() {}

void ArmFunction::SetParent() {}

void ArmFunction::Validate() {}

void ArmFunction::GenAsm(std::ostream& os) const {
    os << "\n    .global " << name << "\n";
    os << name << ":\n";

    std::unordered_set<ArmBlock*> vis;
    std::vector<ArmBlock*> order;
    std::function<void(ArmBlock*)> dfs = [&](ArmBlock* cur) {
        if (vis.count(cur)) return;
        vis.insert(cur);
        order.push_back(cur);
        cur->name = name + ".L" + std::to_string(vis.size());
        for (auto nxt : cur->GetNext()) dfs(nxt);
    };
    dfs(entry);

    int nblk = (int)order.size();
    for (int i = 0; i < nblk; ++i) {
        auto blk = order[i];
        os << blk->name << ":\n";
        for (auto inst : blk->instList) {
            inst->GenAsm(os);
        }
        auto term = blk->GetTerminator();
        if (i + 1 == nblk || term->GetDefaultJump() != order[i + 1]) {
            term->GenJumpAsm(os);
        }
    }
}

void ArmProgram::GenAsm(std::ostream& os) const {
    os << "    .arch armv7ve\n";
    os << "    .fpu vfpv4\n";
    os << "    .arm\n";
    os << "    .data\n";
    for (auto var : globalVars) var.GenAsm(os);

    os << "    .bss\n";
    os << "    .text\n";
    for (auto func : funcs) func->GenAsm(os);
}
